package com.ruoyi.ruoyiserver.utils;

import cn.hutool.core.io.FileUtil;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.ruoyiserver.config.IConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import java.io.*;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

@Slf4j
public class DatabaseUtils {


    /**
     * 执行数据库恢复
     */
    public void restore(String host, String port, String username, String password, String database, String backupFile) {

        try {
            String filePath = backupFile;

            // 如果是压缩文件，先解压
            if (backupFile.endsWith(".gz")) {
                filePath = uncompressFile(backupFile);
            }

            // 构建恢复命令
            String command = String.format(
                    "cmd /c mysql -h%s -P%s -u%s -p%s %s < %s",
                    host, port, username, password, database, filePath
            );
            log.info("command:{}", command);

            // 执行恢复
            Process process = Runtime.getRuntime().exec(
                    command
            );

            // 处理错误输出
            handleErrorStream(process);

            // 等待完成
            int exitCode = process.waitFor();

            if (exitCode != 0) {
                throw new RuntimeException("数据库恢复失败，退出码：" + exitCode);
            }

            log.info("数据库恢复成功");

            FileUtil.del(filePath);
        } catch (Exception e) {
            log.error("数据库恢复异常", e);
            throw new RuntimeException("数据库恢复异常", e);
        }
    }

    /**
     * 解压缩文件
     */
    private String uncompressFile(String gzipFile) throws IOException {
        String outputFile = gzipFile.substring(0, gzipFile.length() - 3);

        try (GZIPInputStream gzis = new GZIPInputStream(
                new FileInputStream(gzipFile));
             FileOutputStream fos = new FileOutputStream(outputFile)) {

            byte[] buffer = new byte[1024];
            int len;
            while ((len = gzis.read(buffer)) > 0) {
                fos.write(buffer, 0, len);
            }
        }

        return outputFile;
    }

    public String beginBack(String host, String username, String password, String port, String database, String filePath) {
        try {
            File file = new File(filePath);
            log.info("文件路径：{}", file.getAbsolutePath());
            file.createNewFile();
            // 构建备份命令
            String command = String.format(
                    "mysqldump -h%s -P%s -u%s -p%s --databases %s -r %s",
                    host, port, username, password, database, filePath
            );
            log.info("sql:{}", command);
            // 执行备份
            Process process = Runtime.getRuntime().exec(command);

            // 处理错误输出
            handleErrorStream(process);

            // 等待完成
            int exitCode = process.waitFor();

            if (exitCode == 0) {
                // 压缩备份文件
                compressBackupFile(filePath);
                log.info("数据库备份成功：{}", filePath);
                return file.getName() + ".gz";
            } else {
                throw new RuntimeException("数据库备份失败，退出码：" + exitCode);
            }

        } catch (Exception e) {
            log.error("数据库备份异常", e);
            throw new RuntimeException("数据库备份异常", e);
        }
    }


    /**
     * 压缩备份文件
     */
    private void compressBackupFile(String filePath) throws IOException {
        try (FileInputStream fis = new FileInputStream(filePath);
             GZIPOutputStream gzos = new GZIPOutputStream(
                     new FileOutputStream(filePath + ".gz"))) {

            byte[] buffer = new byte[1024];
            int len;
            while ((len = fis.read(buffer)) > 0) {
                gzos.write(buffer, 0, len);
            }
        }

        // 删除原始文件
        new File(filePath).delete();
    }

    /**
     * 验证备份文件
     */
    public static void validateBackupFile(String filePath) {
        File file = new File(filePath);
        if (!file.exists()) {
            throw new ServiceException("备份文件不存在：" + filePath);
        }

        if (!file.getName().endsWith(".sql") && !file.getName().endsWith(".sql.gz")) {
            throw new ServiceException("无效的备份文件格式");
        }
    }

    /**
     * 检查磁盘空间
     */
    public static void checkDiskSpace(String path, long requiredSpace) {
        File file = new File(path);
        long usableSpace = file.getUsableSpace();

        if (usableSpace < requiredSpace) {
            throw new ServiceException("磁盘空间不足");
        }
    }


    private void handleErrorStream(Process process) throws IOException {
        try (BufferedReader reader = new BufferedReader(
                new InputStreamReader(process.getErrorStream()))) {
            String line;
            StringBuilder error = new StringBuilder();
            while ((line = reader.readLine()) != null) {
                error.append(line).append("\n");
            }
            if (error.length() > 0) {
                log.error("命令执行错误：{}", error.toString());
            }
        }
    }
}
